﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Tycho.Lexer;
using Tycho.Parser.Peg;
using Tycho.Parser.Tokens;

namespace Tycho.Parser.Tests.Peg {
    [TestFixture]
    public class ChoiceRuleSpecification {
        [Test]
        public void ParseShouldSucceedIfFirstOfTwoRulesSucceeds () {
            Token [] tokens = NativeLexer.Lex ("a").ToArray ();

            ChoiceRule<object> choice = new ChoiceRule<object> (new KeywordRule<object> ("a"), new KeywordRule<object> ("b"));

            var result = choice.Parse (tokens, 0, null);

            Assert.IsNotNull (result);
            Assert.AreEqual (1, result.Index);
        }

        [Test]
        public void ParseShouldSucceedIfSecondOfTwoRulesSucceeds () {
            Token [] tokens = NativeLexer.Lex ("b").ToArray ();

            ChoiceRule<object> choice = new ChoiceRule<object> (new KeywordRule<object> ("a"), new KeywordRule<object> ("b"));

            var result = choice.Parse (tokens, 0, null);

            Assert.IsNotNull (result);
            Assert.AreEqual (1, result.Index);
        }

        [Test]
        public void ParseShouldFailIfNoRuleSucceeds () {
            Token [] tokens = NativeLexer.Lex ("c").ToArray ();

            ChoiceRule<object> choice = new ChoiceRule<object> (new KeywordRule<object> ("a"), new KeywordRule<object> ("b"));

            var result = choice.Parse (tokens, 0, null);

            Assert.IsNull (result);
        }

        [Test]
        public void ParseShouldReturnCorrectIndexForMatchedPattern1 () {
            Token [] tokens = NativeLexer.Lex ("a b").ToArray ();

            ChoiceRule<object> choice = new ChoiceRule<object> (new SequenceRule<object> (new KeywordRule<object> ("a"), new KeywordRule<object> ("b")), new KeywordRule<object> ("c"));

            var result = choice.Parse (tokens, 0, null);

            Assert.IsNotNull (result);
            Assert.AreEqual (2, result.Index);
        }

        [Test]
        public void ParseShouldReturnCorrectIndexForMatchedPattern2 () {
            Token [] tokens = NativeLexer.Lex ("c d").ToArray ();

            ChoiceRule<object> choice = new ChoiceRule<object> (new SequenceRule<object> (new KeywordRule<object> ("a"), new KeywordRule<object> ("b")), new KeywordRule<object> ("c"));

            var result = choice.Parse (tokens, 0, null);

            Assert.IsNotNull (result);
            Assert.AreEqual (1, result.Index);
        }

        [Test]
        public void ParseShouldOnlyTakeSuccessfulContext () {
            Token [] tokens = NativeLexer.Lex ("b").ToArray ();

            var a = new KeywordTerminal<int> ("a");
            a.Action = (term, context) => context + 1;
            var b = new KeywordTerminal<int> ("b");
            b.Action = (term, context) => context + 10;
            var choice = new ChoiceRule<int> (new LiteralRule<int> (a), new LiteralRule<int> (b));

            var result = choice.Parse (tokens, 0, 0);

            Assert.IsNotNull (result);
            Assert.AreEqual (1, result.Index);
            Assert.AreEqual (10, result.Context);
        }

        [Test]
        public void ParseShouldOnlyCaptureSuccessfulRule () {
            Token [] tokens = NativeLexer.Lex ("x a").ToArray ();

            var choice = new ChoiceRule<object> (new NamedRule<object> ("a", new NonTerminal<object> ("x-rule", new SequenceRule<object> (new KeywordRule<object> ("x"), new KeywordRule<object> ("y")))), new NamedRule<object> ("b", new IdentifierTerminal<object> ()));

            var result = choice.Parse (tokens, 0, null);

            Assert.IsNotNull (result);
            Assert.AreEqual (1, result.Index);

            Assert.AreEqual (1, result.Captures.Count);
            result.AssertCaptureIs (0, "b", "x");
        }
    }
}